Though the MTS extended, point source, and etalon data have their fair share of information to share, these are all optical stimuli placed outside of MIRI, observed during a test campaigns on-ground. As such they will not be available to be tested for repeatability during in-flight operations. Here we examine the MIRI internal calibration source observations. This source will also be observed periodically in-flight, thus understanding its behavior, as a "standard" of sorts, is important both in the context of flat-fielding the detector, but also in the context of MIRI fringes. Obviously the light from the MIRI calibration source will also yield a fringe spectrum.
from IPython.display import HTML
HTML('''<script>
code_show=true;
function code_toggle() {
if (code_show){
$('div.input').hide();
} else {
$('div.input').show();
}
code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
The raw code for this IPython notebook is by default hidden for easier reading.
To toggle on/off the raw code, click <a href="javascript:code_toggle()">here</a>.''')
# import modules
import funcs
import mrsobs
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('presentation')
%matplotlib notebook
import warnings
warnings.simplefilter('ignore')
We load the images for one band of the MRS for different kinds of sources, including:
Additionally the pixel-to-wavelength calibration map and the pixel-to-along-slice position map are imported.
# Define paths to data
workDir = '/Users/ioannisa/Desktop/python/miri_devel/'
cdpDir = workDir+'cdp_data/'
d2cMapDir = workDir+'distortionMaps/'
lvl2path = workDir+'FM_data/LVL2/'
# Get data
band = '1A'
ext_source_sci,ext_source_bkg = mrsobs.FM_MTS_BB_extended_source(lvl2path,band,bb_temp='800K')
intcal_source_sci = mrsobs.MIRI_internal_calibration_source(lvl2path,band,campaign='FM')
point_source_sci_p1,point_source_bkg_p1 = mrsobs.FM_MTS_800K_BB_point_source_raster(lvl2path,position='middle',pointing='P3')
# Get wavelength calibration pixel map
d2cMaps = funcs.load_obj('d2cMaps_band{}'.format(band),path=d2cMapDir)
lambdaMap = d2cMaps['lambdaMap']
sliceMap = d2cMaps['sliceMap']
We subtract background exposures where available.
# perform transform
ext_source_bkgsubtr = ext_source_sci-ext_source_bkg
point_source_p1_bkgsubtr = point_source_sci_p1-point_source_bkg_p1
We perform an even-odd row signal correction to the data (caused by the read-out pattern of MIRI detector pixel rows).
ext_source_oddevencorr = funcs.OddEvenRowSignalCorrection(ext_source_bkgsubtr)
intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(intcal_source_sci)
point_source_p1_oddevencorr = funcs.OddEvenRowSignalCorrection(point_source_p1_bkgsubtr)
From MIRI design description report MIRI-DD-00001-AEU: "The calibration system consists of two identical calibration sources for flat-fielding the MIRIM detector array and for flat-fielding the spectrometer detector arrays. The blackbody radiation is produced by micro-miniature tungsten filament lamps and is rendered uniform by a diffusing surface within an optical concentrator. The light is then re-imaged to a pupil placed in the shadow of the secondary mirror."
fig,axs = plt.subplots(2,1,figsize=(10,8))
for row in [255,511,767]:
axs[0].plot(intcal_source_oddevencorr[row,:512],label='detector row {}'.format(row+1))
axs[1].plot(ext_source_oddevencorr[row,:512],label='detector row {}'.format(row+1))
axs[0].set_title('MIRI Internal Calibration Source')
axs[1].set_title('MTS Extended Source')
for plot in range(2):
axs[plot].set_ylim(0)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='lower center')
plt.tight_layout()
Read-out mode for all observations: NFRAME=1, NGROUP=20, NINT=5, READOUT=FAST
CV3_lvl2path = workDir+'CV3_data/LVL2/'
FM_lvl2path = workDir+'FM_data/LVL2/'
OTIS_lvl2path = workDir+'OTIS_data/MRS_RAD_11_CPT/'
CV3_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(CV3_lvl2path,band,campaign='CV3')
FM_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(FM_lvl2path,band,campaign='FM')
OTIS_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(OTIS_lvl2path,band,campaign='OTIS')
CV3_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(CV3_intcal_source_sci)
FM_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(FM_intcal_source_sci)
OTIS_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(OTIS_intcal_source_sci)
row = 512
fig,axs = plt.subplots(2,1,figsize=(10,8))
axs[0].set_title('Detector row 512')
for plot in range(2):
axs[plot].plot(CV3_intcal_source_oddevencorr[row,:512],label='CV3 int cal source obs')
axs[plot].plot(FM_intcal_source_oddevencorr[row,:512],label='FM int cal source obs')
axs[plot].plot(OTIS_intcal_source_oddevencorr[row,:512],label='OTIS int cal source obs')
axs[plot].hlines(0,0,512,linestyle='dashed')
axs[plot].set_ylim(0)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='lower center')
axs[1].set_title('<Zoomed view>')
axs[1].set_xlim(15,40)
axs[1].set_ylim(0,630)
plt.tight_layout()
row = 512
plt.figure(figsize=(10,4))
plt.plot((FM_intcal_source_oddevencorr[row,:512]/CV3_intcal_source_oddevencorr[row,:512] -1)*100.,alpha=0.8,label='CV3 to FM obs')
plt.plot((OTIS_intcal_source_oddevencorr[row,:512]/FM_intcal_source_oddevencorr[row,:512] -1)*100.,label='FM to OTIS obs')
plt.plot((OTIS_intcal_source_oddevencorr[row,:512]/CV3_intcal_source_oddevencorr[row,:512] -1)*100.,alpha=0.4,label='CV3 to OTIS obs')
plt.hlines(0,0,512,linestyle='dashed')
plt.xlim(-25,522)
plt.ylim(-55,110)
plt.xlabel('Detector x-coordinate [pix]')
plt.ylabel('Percentage change [%]')
plt.legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
plt.tight_layout(rect=[0,0,0.83,1])
We use the straylight correction algorithm developed by Adrian Glauser (ETH Zurich) as a quick check on whether the differentiating background between test campaigns could be due to different levels of straylight.
CV3_intcal_source_straylightcorr = funcs.straylightCorrection(CV3_intcal_source_oddevencorr,sliceMap)
FM_intcal_source_straylightcorr = funcs.straylightCorrection(FM_intcal_source_oddevencorr,sliceMap)
OTIS_intcal_source_straylightcorr = funcs.straylightCorrection(OTIS_intcal_source_oddevencorr,sliceMap)
row = 512
fig,axs = plt.subplots(2,1,figsize=(10,8))
axs[0].set_title('Detector row 512')
for plot in range(2):
axs[plot].plot(CV3_intcal_source_straylightcorr[row,:512],label='CV3 int cal source obs')
axs[plot].plot(FM_intcal_source_straylightcorr[row,:512],label='FM int cal source obs')
axs[plot].plot(OTIS_intcal_source_straylightcorr[row,:512],label='OTIS int cal source obs')
axs[plot].hlines(0,0,512,linestyle='dashed')
axs[plot].set_ylim(-100)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
axs[1].set_title('<Zoomed view>')
axs[1].set_xlim(15,40)
axs[1].set_ylim(0,630)
plt.tight_layout(rect=[0,0,0.83,1])
plt.figure(figsize=(10,4))
plt.plot((FM_intcal_source_straylightcorr[row,:512]/CV3_intcal_source_straylightcorr[row,:512] -1)*100.,alpha=0.8,label='CV3 to FM obs')
plt.plot((OTIS_intcal_source_straylightcorr[row,:512]/FM_intcal_source_straylightcorr[row,:512] -1)*100.,label='FM to OTIS obs')
plt.plot((OTIS_intcal_source_straylightcorr[row,:512]/CV3_intcal_source_straylightcorr[row,:512] -1)*100.,alpha=0.4,label='CV3 to OTIS obs')
plt.hlines(0,0,512,linestyle='dashed')
plt.xlim(-25,522)
plt.ylim(-55,110)
plt.xlabel('Detector x-coordinate [pix]')
plt.ylabel('Percentage change [%]')
plt.legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
plt.tight_layout(rect=[0,0,0.83,1])
To ensure that we are looking at the same spatial position of the calibration source illumination, we base our detector pixel tracing on a point source observation rather than the d2c along-slice information.
# pixel trace
ypos_p,xpos_p = funcs.detpixel_trace_compactsource(point_source_p1_oddevencorr,band,d2cMaps)
# signal normalization based on fringe profile
sel = lambdaMap[ypos_p,xpos_p]!=0
intcal_source_norm = funcs.norm_fringe(intcal_source_sci[ypos_p,xpos_p][sel],thres=0.,min_dist=6,k=3,ext=3)
ext_source_norm = funcs.norm_fringe(ext_source_oddevencorr[ypos_p,xpos_p][sel],thres=0.,min_dist=6,k=3,ext=3)
fig,axs = plt.subplots(3,1,figsize=(10,13))
axs[0].set_title('Internal Calibration Source spectrum')
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[0])
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel][intcal_source_norm[1]],intcal_source_norm[0][intcal_source_norm[1]],'ro')
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[2])
axs[0].set_ylim(350,830)
axs[0].set_ylabel('Signal [DN/sec]')
for plot in range(1,3):
axs[plot].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[0]/intcal_source_norm[2],label='Internal Calibration Source')
axs[plot].plot(lambdaMap[ypos_p,xpos_p][sel],ext_source_norm[0]/ext_source_norm[2],label='MTS Extended Source')
axs[plot].hlines(1,4.88,5.77,linestyle='dashed')
axs[plot].set_ylim(0.7,1.05)
axs[plot].set_ylabel('Normalized signal')
axs[1].legend(loc='upper right',bbox_to_anchor=(0.65,1.08),fontsize=10)
axs[2].hlines([0.795,0.912],4.88,5.77,'r',alpha=0.4,linestyle='dashed')
axs[2].set_xlim(5.14,5.31)
axs[2].set_title('<Zoomed view>')
for plot in range(3): axs[plot].set_xlabel('Wavelength [micron]')
plt.tight_layout()
What could be causing the difference in contrast between the fringes of the MIRI internal calibration source and that of the MTS extended source? Could it be that the amplitude of the fringes is proportional to the intensity of the source?